home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Tools & Apps / Testing & Debugging / TV-Man Package / With Source Version / Source / TV-Man.c next >
Encoding:
C/C++ Source or Header  |  1991-11-13  |  17.9 KB  |  665 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    TV-Man.c
  4. #
  5. #    Copyright © Apple Computer, Inc. 1989-1990
  6. #    All rights reserved.
  7. #
  8. #
  9. #    This file contains the functions necessary to control the TV-Man application.
  10. #    TV-Man has the ability to display various patterns on the screen. The ability to
  11. #    generate sounds has been provided as well. 
  12. #
  13. #    In order to have an evironment which predictable events happen several definitions
  14. #    must be established. The most critical is in the file architecture. Each functional
  15. #    block will have its own source and header file. The main project file,  in this
  16. #    case TV-Man, will have its header file included with all other files. This will
  17. #    allow for global constants. The utility source file shall contain functions that
  18. #    are general purpose in nature and that can be used by all other functions. These
  19. #    are intended not to be application or major block specific. In order for this to be 
  20. #    accomodated all functions in the utility source file must use only the information
  21. #    that is passed to them or information that can be gleaned from the system via
  22. #    toolbox calls. There will be no header file associated with the utility file as this
  23. #    will destroy the intent of the utilities.
  24. #
  25. #    There are several files which contain information which is global in nature .These
  26. #    file are included in the main project header file. They are: x.Errors.h, x.Ext.h,
  27. #    x.Protos.h, x.Menus.h. The reason for containing them in seperate files is one of
  28. #    convienience and accesability. 
  29. #
  30. #    Revision Log:
  31. #    
  32. #        11-05-91    RGK        Added the menu items for single color screens
  33. #        04-26-91    RGK        Creation
  34. #
  35. #
  36. ------------------------------------------------------------------------------*/
  37.  
  38. /* This is a list of all local includes necessary for this program.    */
  39.  
  40. #include "TV-Man.h"
  41.  
  42.  
  43.  
  44.  
  45. /*---------------------------------------------------------------------------------------*/
  46. /*    The following lists the globals used in this program. The "g" prefix is
  47.     used to emphasize that a variable is global. 
  48.  
  49.     GMac is used to hold the result of a SysEnvirons call. This makes
  50.     it convenient for any routine to check the environment.        */
  51.  
  52. SysEnvRec    gMac;                /* set up by Initialize */
  53.  
  54.  
  55.  
  56. /*---------------------------------------------------------------------------------------*/
  57. /* GHasWaitNextEvent is set at startup, and tells whether the WaitNextEvent
  58.    trap is available. If it is false, we know that we must call GetNextEvent. */
  59.  
  60. Boolean        gHasWaitNextEvent;    /* set up by Initialize */
  61.  
  62.  
  63.  
  64.  
  65. /*---------------------------------------------------------------------------------------*/
  66. /* GInBackground is maintained by our osEvent handling routines. Any part of
  67.    the program can check it to find out if it is currently in the background. */
  68.  
  69. Boolean        gInBackground;        /* maintained by Initialize and DoEvent */
  70.  
  71.  
  72.  
  73.  
  74. /*---------------------------------------------------------------------------------------*/
  75. /*    This is the number which identifies whch video pattern we will and have displayed    */
  76.  
  77. short        gVideoPattern;
  78. short        gLastVideoPattern;
  79.  
  80.  
  81.  
  82.  
  83.  
  84. /*---------------------------------------------------------------------------------------*/
  85. /*    This routine is part of the MPW runtime library. This external
  86.     reference to it is done so that we can unload its segment, %A5Init. */
  87.  
  88. extern void    _DataInit();
  89.  
  90.  
  91.  
  92.  
  93.  
  94. /*---------------------------------------------------------------------------------------*/
  95. /*    Segmentation strategy:
  96.  
  97.     This program consists of three segments. Main contains most of the code,
  98.     including the MPW libraries, and the main program. Initialize contains
  99.     code that is only used once, during startup, and can be unloaded after the
  100.     program starts. %A5Init is automatically created by the Linker to initialize
  101.     globals for the MPW libraries and is unloaded right away. Each file of C code will
  102.     have a statement at the beginning which will identify the code segment it resides in.    */
  103.  
  104. #pragma segment Main
  105.  
  106.  
  107.  
  108.  
  109.  
  110. /*---------------------------------------------------------------------------------------*/
  111. /*    Now we will start the code        */
  112.     
  113. main()
  114. {
  115.     UnloadSeg((Ptr) _DataInit);        /* note that _DataInit must not be in Main! */
  116.     MaxApplZone();                    /* expand the heap so code segments load at the top */
  117.     Initialize();                    /* initialize the program */
  118.     UnloadSeg((Ptr) Initialize);    /* note that Initialize must not be in Main! */
  119.     SoundInit();                    /* initalize the sound globals    */
  120.     EventLoop();                    /* call the main event loop */
  121. }
  122.  
  123.  
  124.  
  125. /*---------------------------------------------------------------------------------------*/
  126. /*    Get events forever, and handle them by calling DoEvent.
  127.     Get the events by calling WaitNextEvent, if it's available, otherwise
  128.     by calling GetNextEvent. Also call AdjustCursor each time through the loop. */
  129.  
  130. void EventLoop()
  131. {
  132.     RgnHandle        cursorRgn;
  133.     Boolean            gotEvent;
  134.     EventRecord        event;
  135.     Point            mouse;
  136.  
  137.     cursorRgn = NewRgn();        /* we’ll pass WNE an empty region the 1st time thru */
  138.     do
  139.     {
  140.         if ( gHasWaitNextEvent )
  141.         {
  142.             GetGlobalMouse(&mouse);
  143.             AdjustCursor(mouse, cursorRgn);
  144.             gotEvent = WaitNextEvent(everyEvent, &event, MAXLONG, cursorRgn);
  145.         }
  146.         else
  147.         {
  148.             SystemTask();
  149.             gotEvent = GetNextEvent(everyEvent, &event);
  150.         }
  151.         if ( gotEvent )
  152.         {
  153. /* make sure we have the right cursor before handling the event */
  154.             AdjustCursor(event.where, cursorRgn);
  155.             DoEvent(&event);
  156.         }
  157.         SoundCheck();        /* process any sound event necessary    */
  158.     }
  159.     while ( true );                /* loop forever; we quit via ExitToShell */
  160. } /*EventLoop*/
  161.  
  162.  
  163.  
  164.  
  165.  
  166. /*---------------------------------------------------------------------------------------*/
  167. /*    Do the right thing for an event. Determine what kind of event it is, and call
  168.     the appropriate routines. */
  169.  
  170. void DoEvent(event)
  171. EventRecord    *event;
  172. {
  173.     short        part, err;
  174.     WindowPtr    window;
  175.     Boolean        hit;
  176.     char        key;
  177.     Point        aPoint;
  178.  
  179.     switch ( event->what )
  180.     {
  181.         case mouseDown:
  182.             part = FindWindow(event->where, &window);
  183.             switch ( part )
  184.             {
  185.                 case inMenuBar:                /* process a mouse menu command (if any) */
  186.                     AdjustMenus();
  187.                     DoMenuCommand(MenuSelect(event->where));
  188.                     break;
  189.                     
  190.                 case inSysWindow:            /* let the system handle the mouseDown */
  191.                     SystemClick(event, window);
  192.                     break;
  193.                     
  194.                 case inContent:
  195.                     if ( window != FrontWindow() ) SelectWindow(window);
  196.                     break;
  197.                     
  198.                 case inDrag:                /* pass screenBits.bounds to get all gDevices */
  199.                     DragWindow(window, event->where, &qd.screenBits.bounds);
  200.                     break;
  201.                     
  202.                 case inGrow:
  203.                     break;
  204.                     
  205.                 case inZoomIn:
  206.                 case inZoomOut:
  207.                     hit = TrackBox(window, event->where, part);
  208.                     if ( hit )
  209.                     {
  210.                         SetPort(window);                /* the window must be the current port... */
  211.                         EraseRect(&window->portRect);    /* because of a bug in ZoomWindow */
  212.                         ZoomWindow(window, part, true);    /* note that we invalidate and erase... */
  213.                         InvalRect(&window->portRect);    /* to make things look better on-screen */
  214.                     }
  215.                     break;
  216.             }
  217.             break;
  218.             
  219.         case keyDown:
  220.         case autoKey:
  221.             key = event->message & charCodeMask;
  222.             if ( event->modifiers & cmdKey )            /* Command key down */
  223.                 if ( event->what == keyDown )
  224.                 {
  225.                     AdjustMenus();
  226.                     DoMenuCommand(MenuKey(key));
  227.                 }
  228.             break;
  229.             
  230.         case activateEvt:
  231.             DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
  232.             break;
  233.             
  234.         case updateEvt:
  235.             DoUpdate((WindowPtr) event->message);
  236.             break;
  237.             
  238.         case diskEvt:
  239.         /*    It is not a bad idea to at least call DIBadMount in response
  240.             to a diskEvt, so that the user can format a floppy. */
  241.             if ( HiWord(event->message) != noErr )
  242.             {
  243.                 SetPt(&aPoint, kDILeft, kDITop);
  244.                 err = DIBadMount(aPoint, event->message);
  245.             }
  246.             break;
  247.             
  248.         case kOSEvent:
  249.             switch ((event->message >> 24) & 0x0FF)    /*    must BitAND with 0x0FF to get only low byte */
  250.             {
  251.                 case kSuspendResumeMessage:        /* suspend/resume is also an activate/deactivate */
  252.                     gInBackground = (event->message & kResumeMask) == 0;
  253.                     DoActivate(FrontWindow(), !gInBackground);
  254.                     break;
  255.             }
  256.             break;
  257.     }
  258. } /*  DoEvent */
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266. /*---------------------------------------------------------------------------------------*/
  267. /*    Enable and disable menus based on the current state.
  268.     The user can only select enabled menu items. We set up all the menu items
  269.     before calling MenuSelect or MenuKey, since these are the only times that
  270.     a menu item can be selected. Note that MenuSelect is also the only time
  271.     the user will see menu items. This approach to deciding what enable/
  272.     disable state a menu item has the advantage of concentrating all
  273.     the decision-making in one routine, as opposed to being spread throughout
  274.     the application.  */
  275.  
  276. void AdjustMenus()
  277. {
  278.     WindowPtr    window;
  279.     MenuHandle    menu;
  280.  
  281.     window = FrontWindow();
  282.  
  283.     menu = GetMHandle(mFile);
  284.     if ( IsDAWindow(window) )        /* we can allow desk accessories to be closed from the menu */
  285.         EnableItem(menu, iClose);
  286.     else
  287.         DisableItem(menu, iClose);    /* but not this application */
  288.  
  289.     menu = GetMHandle(mEdit);
  290.     if ( IsDAWindow(window) )
  291.     {                                /* a desk accessory might need the edit menu… */
  292.         EnableItem(menu, iUndo);
  293.         EnableItem(menu, iCut);
  294.         EnableItem(menu, iCopy);
  295.         EnableItem(menu, iClear);
  296.         EnableItem(menu, iPaste);
  297.     }
  298.     else
  299.     {                                /* …but we don’t use it */
  300.         DisableItem(menu, iUndo);
  301.         DisableItem(menu, iCut);
  302.         DisableItem(menu, iCopy);
  303.         DisableItem(menu, iClear);
  304.         DisableItem(menu, iPaste);
  305.     }
  306.  
  307.     menu = GetMHandle(mPatterns);
  308.     if ( IsAppWindow(window) )
  309.     {                                
  310.         EnableItem(menu, iTestPattern);
  311.         EnableItem(menu, iColorBars);
  312.         EnableItem(menu, iGrayScaleLD);
  313.         EnableItem(menu, iGrayScaleDL);
  314.         EnableItem(menu, iVLines);
  315.         EnableItem(menu, iHLines);
  316.         EnableItem(menu, iLBurst);
  317.         EnableItem(menu, iRedScreen);
  318.         EnableItem(menu, iGreenScreen);
  319.         EnableItem(menu, iBlueScreen);
  320.         EnableItem(menu, iWhiteScreen);
  321.     }
  322.     else
  323.     {
  324.         DisableItem(menu, iTestPattern);
  325.         DisableItem(menu, iColorBars);
  326.         DisableItem(menu, iGrayScaleLD);
  327.         DisableItem(menu, iGrayScaleDL);
  328.         DisableItem(menu, iVLines);
  329.         DisableItem(menu, iHLines);
  330.         DisableItem(menu, iLBurst);
  331.         DisableItem(menu, iRedScreen);
  332.         DisableItem(menu, iGreenScreen);
  333.         DisableItem(menu, iBlueScreen);
  334.         DisableItem(menu, iWhiteScreen);
  335.     }
  336.  
  337. /*    first clear all the test checkmarks    */
  338.     CheckItem(menu, iTestPattern, false);
  339.     CheckItem(menu, iColorBars, false);
  340.     CheckItem(menu, iGrayScaleLD, false);
  341.     CheckItem(menu, iGrayScaleDL, false);
  342.     CheckItem(menu, iVLines, false);
  343.     CheckItem(menu, iHLines, false);
  344.     CheckItem(menu, iLBurst, false);
  345.     CheckItem(menu, iRedScreen, false);
  346.     CheckItem(menu, iGreenScreen, false);
  347.     CheckItem(menu, iBlueScreen, false);
  348.     CheckItem(menu, iWhiteScreen, false);
  349.     
  350. /*    Now set the correct check mark    */
  351.     CheckItem(menu, gVideoPattern, true);
  352.  
  353.     menu = GetMHandle(mBeeps);
  354.     if ( IsAppWindow(window) )
  355.     {
  356.         EnableItem(menu, iBMSoprano);
  357.         EnableItem(menu, iBMAlto);
  358.         EnableItem(menu, iBMTenor);
  359.         EnableItem(menu, iBMBass);
  360.         EnableItem(menu, iBeepD);
  361.         EnableItem(menu, iBeepE);
  362.     }
  363.     else
  364.     {
  365.         DisableItem(menu, iBMSoprano);
  366.         DisableItem(menu, iBMAlto);
  367.         DisableItem(menu, iBMTenor);
  368.         DisableItem(menu, iBMBass);
  369.         DisableItem(menu, iBeepD);
  370.         DisableItem(menu, iBeepE);
  371.     }
  372. } /* AdjustMenus  */
  373.  
  374.  
  375.  
  376.  
  377. /*---------------------------------------------------------------------------------------*/
  378. /*    This is called when an item is chosen from the menu bar (after calling
  379.     MenuSelect or MenuKey). It performs the right operation for each command.
  380.     It is good to have both the result of MenuSelect and MenuKey go to
  381.     one routine like this to keep everything organized. */
  382.  
  383. void DoMenuCommand(menuResult)
  384.     long        menuResult;
  385. {
  386.     short        menuID;                /* the resource ID of the selected menu */
  387.     short        menuItem;            /* the item number of the selected menu */
  388.     short        itemHit;
  389.     Str255        daName;
  390.     short        daRefNum;
  391.     Boolean        handledByDA;
  392.     WindowPtr    window;
  393.     
  394.     window = FrontWindow();            /* there is only one window so get it */
  395.     menuID = HiWord(menuResult);    /* use macros for efficiency to... */
  396.     menuItem = LoWord(menuResult);    /* get menu item number and menu number */
  397.     switch ( menuID )
  398.     {
  399.         case mApple:
  400.             switch ( menuItem )
  401.             {
  402.                 case iAbout:        /* bring up alert for About */
  403.                     itemHit = Alert(rAboutAlert, nil);
  404.                     break;
  405.                     
  406.                 default:            /* all non-About items in this menu are DAs */
  407.                     GetItem(GetMHandle(mApple), menuItem, daName);
  408.                     daRefNum = OpenDeskAcc(daName);
  409.                     break;
  410.             }
  411.             break;
  412.             
  413.         case mFile:
  414.             switch ( menuItem )
  415.             {
  416.                 case iClose:
  417.                     DoCloseWindow(FrontWindow());
  418.                     break;
  419.                     
  420.                 case iQuit:
  421.                     Terminate();
  422.                     break;
  423.             }
  424.             break;
  425.             
  426.         case mEdit:                    /* call SystemEdit for DA editing & MultiFinder */
  427.             handledByDA = SystemEdit(menuItem-1);    /* since we don’t do any Editing */
  428.             break;
  429.             
  430.         case mPatterns:
  431.             gLastVideoPattern = gVideoPattern;        /* save the current Pattern    */
  432.             switch ( menuItem )
  433.             {
  434.                 case iTestPattern:
  435.                     gVideoPattern = iTestPattern;
  436.                     break;
  437.     
  438.                 case iColorBars:
  439.                     gVideoPattern = iColorBars;
  440.                     break;
  441.                     
  442.                 case iGrayScaleLD:
  443.                     gVideoPattern = iGrayScaleLD;
  444.                     break;
  445.                 
  446.                 case iGrayScaleDL:
  447.                     gVideoPattern = iGrayScaleDL;
  448.                     break;
  449.                 
  450.                 case iVLines:
  451.                     gVideoPattern = iVLines;
  452.                     break;
  453.                 
  454.                 case iHLines:
  455.                     gVideoPattern = iHLines;
  456.                     break;
  457.  
  458.                 case iLBurst:
  459.                     gVideoPattern = iLBurst;
  460.                     break;
  461.  
  462.                 case iRedScreen:
  463.                     gVideoPattern = iRedScreen;
  464.                     break;
  465.  
  466.                 case iGreenScreen:
  467.                     gVideoPattern = iGreenScreen;
  468.                     break;
  469.  
  470.                 case iBlueScreen:
  471.                     gVideoPattern = iBlueScreen;
  472.                     break;
  473.  
  474.                 case iWhiteScreen:
  475.                     gVideoPattern = iWhiteScreen;
  476.                     break;
  477.             }
  478.             InvalRect(&window->portRect);        /* invalidate the area to force an update */
  479.             break;
  480.             
  481.         case mBeeps:
  482.             switch ( menuItem )
  483.             {
  484.                 case iBMSoprano:
  485.                     SopranoControls();
  486.                     break;
  487.                     
  488.                 case iBMAlto:
  489.                     AltoControls();
  490.                     break;
  491.                     
  492.                 case iBMTenor:
  493.                     TenorControls();
  494.                     break;
  495.                     
  496.                 case iBMBass:
  497.                     BassControls();    
  498.                     break;
  499.                     
  500.                 case iBeepD:
  501.                     ClearAllSounds();    
  502.                     KillSoundChannels();    
  503.                     break;
  504.                     
  505.                 case iBeepE:
  506.                     SetAllSounds();    
  507.                     break;
  508.                     
  509.             }
  510.             break;
  511.     }
  512.     HiliteMenu(0);                    /* unhighlight what MenuSelect (or MenuKey) hilited */
  513. } /* DoMenuCommand */
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521. /*---------------------------------------------------------------------------------------*/
  522. /*    Change the cursor's shape, depending on its position. This also calculates the region
  523.     where the current cursor resides (for WaitNextEvent). If the mouse is ever outside of
  524.     that region, an event would be generated, causing this routine to be called,
  525.     allowing us to change the region to the region the mouse is currently in. If
  526.     there is more to the event than just “the mouse moved”, we get called before the
  527.     event is processed to make sure the cursor is the right one. In any (ahem) event,
  528.     this is called again before we fall back into WNE. */
  529.  
  530. void AdjustCursor(mouse,region)
  531. Point        mouse;
  532.     RgnHandle    region;
  533. {
  534.     WindowPtr    window;
  535.     RgnHandle    arrowRgn;
  536.     RgnHandle    plusRgn;
  537.     Rect        globalPortRect;
  538.  
  539.     window = FrontWindow();                    /* we only adjust the cursor when we are in front */
  540.     if ( (! gInBackground) && (! IsDAWindow(window)) )
  541.     {
  542.         arrowRgn = NewRgn();                /* calculate regions for different cursor shapes */
  543.         plusRgn = NewRgn();
  544.         
  545.     /* start with a big, big rectangular region */
  546.         SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  547.  
  548.         if ( IsAppWindow(window) )            /* calculate plusRgn */
  549.         {
  550.             SetPort(window);                /* make a global version of the viewRect */
  551.             SetOrigin(-window->portBits.bounds.left, -window->portBits.bounds.top);
  552.             globalPortRect = window->portRect;
  553.             RectRgn(plusRgn, &globalPortRect);
  554.             SectRgn(plusRgn, window->visRgn, plusRgn);
  555.             SetOrigin(0, 0);
  556.         }
  557.  
  558.         DiffRgn(arrowRgn, plusRgn, arrowRgn);    /* subtract other regions from arrowRgn */
  559.  
  560.         if ( PtInRgn(mouse, plusRgn) )            /* change the cursor and the region parameter */
  561.         {
  562.             SetCursor(*GetCursor(plusCursor));
  563.             CopyRgn(plusRgn, region);
  564.         }
  565.         else
  566.         {
  567.             SetCursor(&qd.arrow);
  568.             CopyRgn(arrowRgn, region);
  569.         }
  570.  
  571.         DisposeRgn(arrowRgn);        /* get rid of our local regions */
  572.         DisposeRgn(plusRgn);
  573.     }
  574. } /* AdjustCursor */
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581. /*---------------------------------------------------------------------------------------*/
  582. /*    Draw the contents of the application window. This will be black and white on old
  583.     machines, but color on color machines. At this point, the window’s visRgn
  584.     is set to allow drawing only where it needs to be done. */
  585.  
  586. void DrawWindow(window)
  587.     WindowPtr    window;
  588. {
  589.     SetPort(window);
  590.     EraseRect(&window->portRect);    /* clear out any garbage that may linger */
  591.     
  592.     switch (gVideoPattern)
  593.     {
  594.         case iTestPattern:
  595.             DrawTestPattern(window);
  596.             break;
  597.             
  598.         case iColorBars:
  599.             DrawColorBars(window);
  600.             break;
  601.         
  602.         case iGrayScaleLD:
  603.             DrawGrayScaleLD(window);
  604.             break;
  605.         
  606.         case iGrayScaleDL:
  607.             DrawGrayScaleDL(window);
  608.             break;
  609.  
  610.         case iVLines:
  611.             DrawVertLines(window);
  612.             break;
  613.  
  614.         case iHLines:
  615.             DrawHorzLines(window);
  616.             break;
  617.  
  618.         case iLBurst:
  619.             DrawLineBurst(window);
  620.             break;
  621.  
  622.         case iRedScreen:
  623.             DrawRedScreen(window);
  624.             break;
  625.  
  626.         case iGreenScreen:
  627.             DrawGreenScreen(window);
  628.             break;
  629.  
  630.         case iBlueScreen:
  631.             DrawBlueScreen(window);
  632.             break;
  633.  
  634.         case iWhiteScreen:
  635.             DrawWhiteScreen(window);
  636.             break;
  637.     }
  638. } /* DrawWindow */
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645. /*---------------------------------------------------------------------------------------*/
  646. /*    Check to see if a given trap is implemented. This is only used by the Initialize
  647.     routine in this program. The recommended approach to see if a trap is implemented
  648.     is to see if the address of the trap routine is the same as the address of the
  649.     Unimplemented trap. Needs to be called after call to SysEnvirons so that it can check
  650.     if a ToolTrap is out of range of a pre-MacII ROM. */
  651.  
  652. Boolean TrapAvailable(tNumber,tType)
  653. short        tNumber;
  654. TrapType    tType;
  655. {
  656.     if ( ( tType == ToolTrap ) &&
  657.                     ( gMac.machineType > envMachUnknown ) &&
  658.                     ( gMac.machineType < envMacII ) )
  659.     {                                            /* it's a 512KE, Plus, or SE */
  660.         tNumber = tNumber & 0x03FF;
  661.         if ( tNumber > 0x01FF )                    /* which means the tool traps */
  662.             tNumber = _Unimplemented;            /* only go to 0x01FF */
  663.     }
  664.     return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
  665. } /* TrapAvailable */